/*
 *  Arrow
 *
 *  Created by David Giovannini on 1/5/07.
 *  Copyright 2007 Software by Jove. All rights reserved.
 *
 */
 
#if defined(WIN32)
#include "SBJ/Thread/Stamp.h"

#pragma warning( push )
#pragma warning( disable : 4244 ) // boost needs some static casts
//#include "boost/date_time/posix_time/posix_time.hpp" 
#include <windows.h>
#undef max // boost includes windows.h !
#undef min // boost includes windows.h !
#pragma warning( pop )

#include <assert.h>

namespace SBJ
{

namespace
{

struct ProcessInfo
{
	ProcessInfo( void )
	: id( static_cast< int >( ::GetCurrentProcessId() ) )
	{
	// Pathname
		char buffer[ 256 ] = "";
		DWORD len = ::GetModuleFileName( NULL, buffer, sizeof( buffer ) );
		pathName = buffer;

	// Module name
		{
			bool extFound = false;
			char* findName = ( buffer + len );
			while ( *findName != '\\' && *findName != '/' && findName >= buffer )
			{
				if ( *findName == '.' && extFound == false )
				{
					*findName = 0;
					extFound = true;
				}
				--findName;
			}
			name = findName + 1;
		}

	// Identifier
		{
			char buffer[ 256 ] = "";
			DWORD size = sizeof( buffer );
			::GetComputerName( buffer, &size );
			computerName = buffer;
		}

	// Version
		{
			DWORD unused = 0;
			DWORD versionSize = ::GetFileVersionInfoSize( pathName.c_str(), &unused );
			DWORD err = GetLastError();
			if ( versionSize > 0 )
			{
				UINT len = 0;
				char* versionBuf = new char[ versionSize ];
				if ( ::GetFileVersionInfo( pathName.c_str(), 0, versionSize, versionBuf ) != 0 )
				{
					VS_FIXEDFILEINFO* info = 0;
					if ( ::VerQueryValue( versionBuf, "\\", (LPVOID*)&info, &len ) != 0 )
					{
						version.file[ 3 ] = (short)(info->dwFileVersionMS >> 16);
						version.file[ 2 ] = (short)(info->dwFileVersionMS & 0x0000FFFF);
						version.file[ 1 ] = (short)(info->dwFileVersionLS >> 16);
						version.file[ 0 ] = (short)(info->dwFileVersionLS & 0x0000FFFF);
						version.product[ 3 ] = (short)(info->dwProductVersionMS >> 16);
						version.product[ 2 ] = (short)(info->dwProductVersionMS & 0x0000FFFF);
						version.product[ 1 ] = (short)(info->dwProductVersionLS >> 16);
						version.product[ 0 ] = (short)(info->dwProductVersionLS & 0x0000FFFF);
					}
				}
				delete[] versionBuf;
			}
		}
	}

	int id;
	std::string name;
	std::string pathName;
	std::string computerName;
	Stamp::Version version;
};

ProcessInfo myProcess;

}

Stamp::Version::Version( void )
#if defined( _DEBUG )
: debug( true )
#else
: debug( false )
#endif
{
	::memset( &file, 0, sizeof( file ) );
	::memset( &product, 0, sizeof( product ) );
}

Stamp::Stamp( void )
: m_time()
, m_threadID( static_cast< int >( ::GetCurrentThreadId() ) )
{
	assert( sizeof( FILETIME ) == sizeof( long long ) );
	assert( sizeof( long long ) == sizeof( __int64 ) );

	::GetSystemTimeAsFileTime( (LPFILETIME)&m_time );
}

Stamp::~Stamp( void )
{
}

void
Stamp::reset( void )
{
	m_threadID = static_cast< int >( ::GetCurrentThreadId() );
	::GetSystemTimeAsFileTime( (LPFILETIME)&m_time );
}

const Stamp::Time&
Stamp::getTime( void ) const
{
	return m_time;
}

int
Stamp::getThreadId( void ) const
{
	return m_threadID;
}

int
Stamp::getProcessId( void )
{
	return myProcess.id;
}

const std::string&
Stamp::getProcessName( void )
{
	return myProcess.name;
}

const std::string&
Stamp::getProcessPathName( void )
{
	return myProcess.pathName;
}

const Stamp::Version&
Stamp::getProcessVersion( void )
{
	return myProcess.version;
}

const std::string&
Stamp::getComputerName( void )
{
	return myProcess.computerName;
}

}
#endif